home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 14 / Example 14.1 / GroupAI.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-01  |  6.3 KB  |  305 lines

  1. #include "groupAI.h"
  2. #include "masterAI.h"
  3. #include "strategyMap.h"
  4.  
  5. GROUPAI::GROUPAI(MASTERAI *_master)
  6. {
  7.     m_pMaster = _master;
  8.     m_task = TASK_NONE;
  9.     m_state = GROUP_STATE_IDLE;
  10. }
  11.  
  12. GROUPAI::~GROUPAI()
  13. {
  14.     //Reset group pointer for all group members
  15.     for(int i=0;i<m_members.size();i++)
  16.         m_members[i]->m_pGroup = NULL;
  17. }
  18.  
  19. void GROUPAI::AddMember(MAPOBJECT *newMember)
  20. {
  21.     if(Find(m_members, newMember) < 0)
  22.     {
  23.         newMember->m_pGroup = this;    
  24.         m_members.push_back(newMember);
  25.     }
  26. }
  27.  
  28. void GROUPAI::RemoveMember(MAPOBJECT *oldMember)
  29. {
  30.     int place = Find(m_members, oldMember);
  31.  
  32.     if(place >= 0)
  33.     {
  34.         oldMember->m_pGroup = NULL;
  35.         m_members.erase(&m_members[place]);
  36.     }
  37. }
  38.  
  39. void GROUPAI::DisbandGroup()
  40. {
  41.     while(!m_members.empty())
  42.     {
  43.         RemoveMember(m_members[0]);
  44.     }
  45.  
  46.     m_members.clear();
  47.     m_visibleEnemies.clear();
  48. }
  49.  
  50. void GROUPAI::EnemiesSpotted(std::vector<MAPOBJECT*> &manyEnemies)
  51. {
  52.     //This function is used by units to report spotted enemy units
  53.  
  54.     if(m_visibleEnemies.size() > 30)return;
  55.  
  56.     for(int i=0;i<manyEnemies.size();i++)
  57.         if(Find(m_visibleEnemies, manyEnemies[i]) < 0)
  58.             m_visibleEnemies.push_back(manyEnemies[i]);
  59. }
  60.  
  61. void GROUPAI::SetTask(int newTask, RECT *area)
  62. {
  63.     m_task = newTask;
  64.  
  65.     if(area == NULL)
  66.         m_task = TASK_NONE;
  67.     else m_mapArea = *area;
  68. }
  69.  
  70. GROUPAI* GROUPAI::SplitGroup(std::vector<int> units)
  71. {
  72.     //This function splits the group according to the wishlist (units)
  73.  
  74.     if(units.empty() || m_members.empty())return NULL;
  75.  
  76.     GROUPAI *newGroup = new GROUPAI(m_pMaster);
  77.  
  78.     try
  79.     {
  80.         bool done = false;
  81.  
  82.         while(!done)
  83.         {
  84.             //Transfer member
  85.             for(int i=0;i<m_members.size();i++)
  86.                 if(!m_members[i]->m_isBuilding && m_members[i]->m_type == units[0])
  87.                 {    
  88.                     MAPOBJECT* unit = m_members[i];
  89.                     RemoveMember(unit);
  90.                     newGroup->AddMember(unit);
  91.                     break;
  92.                 }
  93.             
  94.             units.erase(units.begin());
  95.             done = units.empty() || m_members.empty();
  96.         }
  97.  
  98.         if(newGroup->isDead())
  99.         {
  100.             delete newGroup;
  101.             newGroup = NULL;
  102.         }
  103.     }
  104.     catch(...)
  105.     {
  106.         debug.Print("Error in GROUPAI::SplitGroup()");
  107.     }
  108.  
  109.     return newGroup;
  110. }
  111.  
  112. void GROUPAI::Goto(RECT mArea)
  113. {
  114.     if(m_members.empty())return;
  115.  
  116.     //Move group to area
  117.  
  118.     try
  119.     {
  120.         for(int i=0;i<m_members.size();i++)
  121.             if(m_members[i] != NULL && !m_members[i]->m_isBuilding && !m_members[i]->m_dead)
  122.             {
  123.                 UNIT *unit = (UNIT*)m_members[i];
  124.  
  125.                 if(unit->m_state != STATE_ATTACK)
  126.                 {
  127.                     INTPOINT p(rand()%(mArea.right - mArea.left) + mArea.left,
  128.                                 rand()%(mArea.bottom - mArea.top) + mArea.top);
  129.  
  130.                     p = unit->m_pTerrain->GetClosestFreeTile(p, unit->m_mappos);
  131.                     unit->m_pTarget = NULL;
  132.                     unit->Goto(p, false, true, STATE_MOVING);
  133.                 }
  134.             }
  135.     }
  136.     catch(...){}
  137. }
  138.  
  139. void GROUPAI::Attack(std::vector<MAPOBJECT*> &enemies)
  140. {
  141.     //Attack enemies
  142.  
  143.     for(int i=0;i<m_members.size();i++)
  144.         if(!m_members[i]->m_isBuilding && !m_members[i]->m_dead)
  145.         {
  146.             UNIT *unit = (UNIT*)m_members[i];
  147.  
  148.             if(unit->m_state == STATE_IDLE || unit->m_state == STATE_MOVING)
  149.                 unit->Attack(unit->BestTargetToAttack(enemies));
  150.         }
  151. }
  152.  
  153. void GROUPAI::RetreatTo(RECT ma)
  154. {
  155.     if(m_members.empty())return;
  156.  
  157.     for(int i=0;i<m_members.size();i++)
  158.         if(!m_members[i]->m_isBuilding && !m_members[i]->m_dead)
  159.         {
  160.             UNIT *unit = (UNIT*)m_members[i];
  161.  
  162.             if(!unit->m_mappos.inRect(ma))
  163.             {
  164.                 INTPOINT p(rand()%(ma.right - ma.left) + ma.left,
  165.                             rand()%(ma.bottom - ma.top) + ma.top);
  166.  
  167.                 p = unit->m_pTerrain->GetClosestFreeTile(p, unit->m_mappos);
  168.                 unit->m_pTarget = NULL;
  169.                 unit->Goto(p, false, true, STATE_RETREAT);
  170.             }
  171.         }
  172.  
  173.     m_mapArea = ma;
  174. }
  175.  
  176. void GROUPAI::Shuffle()
  177. {
  178.     //Random movement
  179.  
  180.     if(m_members.empty())return;
  181.  
  182.     for(int i=0;i<m_members.size();i++)
  183.         if(!m_members[i]->m_isBuilding && !m_members[i]->m_dead && rand()%40 == 0)
  184.         {
  185.             UNIT *unit = (UNIT*)m_members[i];
  186.  
  187.             INTPOINT p(rand()%(m_mapArea.right - m_mapArea.left) + m_mapArea.left,
  188.                         rand()%(m_mapArea.bottom - m_mapArea.top) + m_mapArea.top);
  189.  
  190.             p = unit->m_pTerrain->GetClosestFreeTile(p, unit->m_mappos);
  191.             unit->m_pTarget = NULL;
  192.             unit->Goto(p, false, true, STATE_MOVING);                        
  193.         }
  194. }
  195.  
  196. void GROUPAI::GroupAI()
  197. {
  198.     if(m_members.empty() || m_pMaster == NULL)return;
  199.  
  200.     int memberStates[] = {0, 0, 0};
  201.     m_state = GROUP_STATE_IDLE;
  202.  
  203.     std::vector<MAPOBJECT*>::iterator i;
  204.     for(i = m_members.begin();i != m_members.end();)
  205.     {
  206.         if((*i) == NULL || (*i)->m_dead)
  207.         {
  208.             //Remove dead Group m_members
  209.             RemoveMember(*i);
  210.         }
  211.         else 
  212.         {
  213.             (*i)->m_pGroup = this;
  214.  
  215.             //determine group m_state
  216.             if(!(*i)->m_isBuilding)
  217.             {
  218.                 UNIT *unit = (UNIT*)(*i);
  219.                 
  220.                 if(unit->m_state == STATE_ATTACK)
  221.                     memberStates[GROUP_STATE_BATTLE]++;
  222.                 else if(unit->m_moving)
  223.                     memberStates[GROUP_STATE_MOVING]++;
  224.                 else memberStates[GROUP_STATE_IDLE]++;
  225.             }
  226.             i++;
  227.         }
  228.     }
  229.  
  230.     //Set group state
  231.     if(memberStates[GROUP_STATE_BATTLE] >= m_members.size() * 0.2f)
  232.         m_state = GROUP_STATE_BATTLE;
  233.     else if(memberStates[GROUP_STATE_MOVING] >= m_members.size() * 0.4f)
  234.         m_state = GROUP_STATE_MOVING;
  235.     else m_state = GROUP_STATE_IDLE;
  236.  
  237.     //Group state machine
  238.     switch(m_state)
  239.     {
  240.         case GROUP_STATE_IDLE:
  241.         {            
  242.             if(m_task == TASK_SCOUT)
  243.             {
  244.                 AREA *area = m_pMaster->m_pStrategyMap->GetScoutArea(GetCenter());
  245.                 if(area != NULL)Goto(area->m_mapArea);
  246.             }
  247.             else if(m_task == TASK_ATTACK_LOCATION)
  248.             {
  249.                 AREA *area = m_pMaster->m_pStrategyMap->GetAttackArea(GetCenter());
  250.                 if(area != NULL)Goto(area->m_mapArea);                
  251.             }
  252.             else if(m_task == TASK_NONE || m_task == TASK_DEFEND_LOCATION)
  253.             {
  254.                 Shuffle();
  255.             }
  256.  
  257.             break;
  258.         }
  259.         case GROUP_STATE_MOVING:
  260.         {
  261.             Attack(m_visibleEnemies);
  262.  
  263.             break;
  264.         }
  265.         case GROUP_STATE_BATTLE:
  266.         {
  267.             Attack(m_visibleEnemies);
  268.  
  269.             if(m_task == TASK_DEFEND_LOCATION)
  270.                 RetreatTo(m_mapArea);
  271.  
  272.             break;
  273.         }
  274.     }
  275.  
  276.     //Report enemies to Master AI
  277.     m_pMaster->EnemiesSpotted(m_visibleEnemies);
  278.     m_visibleEnemies.clear();
  279. }
  280.  
  281. bool GROUPAI::isDead()
  282. {
  283.     return m_members.empty();
  284. }
  285.  
  286. INTPOINT GROUPAI::GetCenter()
  287. {
  288.     INTPOINT p;
  289.  
  290.     try
  291.     {
  292.         if(m_members.size() <= 0)return p;
  293.  
  294.         for(int i=0;i<m_members.size();i++)
  295.             p += m_members[i]->m_mappos;
  296.  
  297.         p /= m_members.size();
  298.     }
  299.     catch(...)
  300.     {
  301.         debug.Print("Error in GROUPAI::GetCenter()");
  302.     }
  303.  
  304.     return p;
  305. }